package com.sise.DP;

/**
 *      剑指 Offer 47. 礼物的最大价值
 *
 *      在一个 m*n 的棋盘的每一格都放有一个礼物，每个礼物都有一定的价值（价值大于 0）。你可以从棋盘的左上角开始拿格子里的礼物，并每次向右或者向下移动一格、直到到达棋盘的右下角。
 *      给定一个棋盘及其上面的礼物的价值，请计算你最多能拿到多少价值的礼物？
 *
 *      输入:
 *      [
 *       [1,3,1],
 *       [1,5,1],
 *       [4,2,1]
 *      ]
 *      输出: 12
 *      解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
 */
public class _offer_47_maxValue {

    /**
     *      动态规划原始版本 (太快乐了!!!.. 后面的二维数组做不出来，滚动数组又被 dp[] 迷惑了，又伤心了~ )
     *      这里要注意 dp 的 base case，它也需要累加
     */
    public int maxValue(int[][] grid) {
        if (grid == null) return 0;
        int[][] dp = new int[grid.length][grid[0].length];

        dp[0][0] = grid[0][0];
        for (int i = 1; i < dp.length; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int i = 1; i < dp[0].length; i++) {
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }

        for (int i = 1; i < grid.length; i++){
            for (int j = 1; j < grid[0].length; j++){
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[grid.length - 1][grid[0].length - 1];
    }

    /**
     *      动态规划使用两行 (用两行的话，写不出来，翻遍全网都没找到)
     */
    public int maxValue_2(int[][] grid) {
        return 0;
    }

    /**
     *      动态规划 - 滚动数组
     *
     *      最重要的是理解 dp[] 的含义，这里的 dp[] 为上一层的可选择的最大数值，而不是 上一层的原始数据，因为原始数据在 grid[][] 中已经给出。
     */
    public int maxValue_3(int[][] grid) {
        if (grid == null || grid.length == 0) return 0;

        int[] dp = new int[grid[0].length + 1];             // 这里在原始的长度上 +1，故此在下面的循环中，需要加个 等于号

        for (int i = 1; i <= grid.length; i++){             // 这里是 小于等于，因为只有 等于了，才是 完整的一行数据(列数完整)
            for (int j = 1; j <= grid[0].length; j++){
                dp[j] = Math.max(dp[j], dp[j - 1]) + grid[i - 1][j - 1];    // dp[j]：上一层的数据(上一次遍历留下来的数据) dp[j-1]：当前位置的左边数据。
                                                                            // 由于 dp[] 是加一后的结果，故此 grid 的 i、j 都需要减一
            }
        }
        return dp[grid[0].length];                          // 以往拿的值都是 length - 1，所以在这里就是 length
    }
}